/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* define to prevent recursive inclusion -------------------------------------*/
#ifndef __PONY_PRIVATE_ATOMIC_H__
#define __PONY_PRIVATE_ATOMIC_H__

/* includes (standard library, system) ---------------------------------------*/
#include <stdbool.h>
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <x_atomic.h>
#include <x_compiler.h>
/* includes (local) ----------------------------------------------------------*/
#include <a_it.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/

#define ATOMIC_MATH(opr, type)                                                                     \
    do {                                                                                           \
        unsigned long flags = it_lock();                                                           \
        type old = a->val;                                                                         \
        a->val = a->val opr v;                                                                     \
        it_restore(flags);                                                                         \
        return old;                                                                                \
    } while (0)

/* inlines -------------------------------------------------------------------*/

/**
 * atomic_int_add - atomic add value to an atomic_int variable
 * @a: address of the atomic_int variable
 * @v: the value to be added
 *
 * return: the original value of the atomic_int variable
 */
static __always_inline int atomic_int_add(atomic_int *a, int v)
{
    ATOMIC_MATH(+, int);
}

/**
 * atomic_uint_add - atomic add value to an atomic_uint variable
 * @a: address of the atomic_uint variable
 * @v: the value to be added
 *
 * return: the original value of the atomic_uint variable
 */
static __always_inline unsigned int atomic_uint_add(atomic_uint *a, unsigned int v)
{
    ATOMIC_MATH(+, unsigned int);
}

/**
 * atomic_int_sub - atomic sub value from an atomic_int variable
 * @a: address of the atomic_int variable
 * @v: the value to sub
 *
 * return: the original value of the atomic_int variable
 */
static __always_inline int atomic_int_sub(atomic_int *a, int v)
{
    ATOMIC_MATH(-, int);
}

/**
 * atomic_uint_sub - atomic sub value from an atomic_uint variable
 * @a: address of the atomic_uint variable
 * @v: the value to sub
 *
 * return: the original value of the atomic_uint variable
 */
static __always_inline unsigned int atomic_uint_sub(atomic_uint *a, unsigned int v)
{
    ATOMIC_MATH(-, unsigned int);
}

/**
 * atomic_int_and - atomic bitwise and value with an atomic_int variable
 * @a: address of the atomic_int object
 * @v: the value to sub
 *
 * return: the original value of the atomic_int variable
 */
static __always_inline int atomic_int_and(atomic_int *a, int v)
{
    ATOMIC_MATH(&, int);
}

/**
 * atomic_uint_and - atomic bitwise and value with an atomic_uint variable
 * @a: address of the atomic_uint object
 * @v: the value to sub
 *
 * return: the original value of the atomic_uint variable
 */
static __always_inline unsigned int atomic_uint_and(atomic_uint *a, unsigned int v)
{
    ATOMIC_MATH(&, unsigned int);
}

/**
 * atomic_int_orr - atomic bitwise orr value with an atomic_int variable
 * @a: address of the atomic_int variable
 * @v: the value to sub
 *
 * return: the original value of the atomic_int variable
 */
static __always_inline int atomic_int_orr(atomic_int *a, int v)
{
    ATOMIC_MATH(|, int);
}

/**
 * atomic_uint_orr - atomic bitwise orr value with an atomic_uint variable
 * @a: address of the atomic_uint variable
 * @v: the value to sub
 *
 * return: the original value of the atomic_uint variable
 */
static __always_inline unsigned int atomic_uint_orr(atomic_uint *a, unsigned int v)
{
    ATOMIC_MATH(|, unsigned int);
}

/**
 * atomic_int_xor - atomic bitwise xor value with an atomic_int variable
 * @a: address of the atomic_int object
 * @v: the value to sub
 *
 * return: the original value of the atomic_int variable
 */
static __always_inline int atomic_int_xor(atomic_int *a, int v)
{
    ATOMIC_MATH(^, int);
}

/**
 * atomic_uint_xor - atomic bitwise xor value with an atomic_uint variable
 * @a: address of the atomic_uint object
 * @v: the value to sub
 *
 * return: the original value of the atomic_uint variable
 */
static __always_inline unsigned int atomic_uint_xor(atomic_uint *a, unsigned int v)
{
    ATOMIC_MATH(^, unsigned int);
}

/**
 * atomic_int_inc - increase an atomic_int variable by 1
 * @a: address of the atomic_int variable
 *
 * return: the original value of the atomic variable
 */
static __always_inline int atomic_int_inc(atomic_int *a)
{
    return atomic_int_add(a, 1);
}

/**
 * atomic_uint_inc - increase an atomic_uint variable by 1
 * @a: address of the atomic_uint variable
 *
 * return: the original value of the atomic variable
 */
static __always_inline unsigned int atomic_uint_inc(atomic_uint *a)
{
    return atomic_uint_add(a, 1);
}

/**
 * atomic_int_dec - decrease an atomic_int variable by 1
 * @a: address of the atomic_int object
 *
 * return: the original value of the atomic_int variable
 */
static __always_inline int atomic_int_dec(atomic_int *a)
{
    return atomic_int_add(a, -1);
}

/**
 * atomic_uint_dec - decrease an atomic_uint variable by 1
 * @a: address of the atomic_uint object
 *
 * return: the original value of the atomic_uint variable
 */
static __always_inline unsigned int atomic_uint_dec(atomic_uint *a)
{
    return atomic_uint_add(a, (unsigned int)-1);
}

/**
 * atomic_int_set_eq - set the value (v) of a atomic_int object if equal its value
 *                     equal to (o)
 * @a: address of the atomic_int object
 * @o: old value expected
 * @v: new value to set
 *
 * return: true if the set is actually executed, FALSE otherwise
 */
static __always_inline bool atomic_int_set_eq(atomic_int *a, int o, int v)
{
    bool ret;

    unsigned long flags = it_lock();
    if (a->val != o) {
        ret = false;
    } else {
        a->val = v;
        ret = true;
    }
    it_restore(flags);

    return ret;
}

/**
 * atomic_uint_set_eq - set the value (v) of a atomic_uint object if its value
 *                      equal to (o)
 * @a: address of the atomic_uint object
 * @o: old value expected
 * @v: new value to set
 *
 * return: true if the set is actually executed, FALSE otherwise
 */
static __always_inline bool atomic_uint_set_eq(atomic_uint *a, int o, int v)
{
    return atomic_int_set_eq((atomic_int *)a, (int)o, (int)v);
}

/**
 * atomic_int_add_ne - add the value (v) to a atomic_int object if its value not
 *                     equal to (o)
 * @a: address of the atomic_int object
 * @o: old value expected
 * @v: new value to add
 *
 * return: true if the value is added
 */
static __always_inline bool atomic_int_add_ne(atomic_int *a, int o, int v)
{
    bool ret;

    unsigned long flags = it_lock();
    if (a->val == o) {
        ret = false;
    } else {
        a->val += v;
        ret = true;
    }
    it_restore(flags);

    return ret;
}

/**
 * atomic_uint_add_ne - add the value (v) to a atomic_uint object if its value not
 *                      equal to (o)
 * @a: address of the atomic_uint object
 * @o: old value expected
 * @v: new value to add
 *
 * return: true if the value is added
 */
static __always_inline bool atomic_uint_add_ne(atomic_uint *a, unsigned int o, unsigned int v)
{
    return atomic_int_add_ne((atomic_int *)a, (int)o, (int)v);
}

/**
 * atomic_int_dec_nz - decrease a atomic_int variable if it is not zero
 * @a: address of the atomic_int object
 *
 * return: true if the value is added
 */
static __always_inline bool atomic_int_dec_nz(atomic_int *a)
{
    return atomic_int_add_ne(a, 0, -1);
}

/**
 * atomic_uint_dec_nz - decrease a atomic_uint variable if it is not zero
 * @a: address of the atomic_uint object
 *
 * return: true if the value is added
 */
static __always_inline bool atomic_uint_dec_nz(atomic_uint *a)
{
    return atomic_int_add_ne((atomic_int *)a, 0, (int)-1);
}

/* externs -------------------------------------------------------------------*/

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __PONY_PRIVATE_ATOMIC_H__ */
